//
//  Server.m
//  Server
//
//  Created by 蒋杏飞 on 15/5/20.
//  Copyright (c) 2015年 蓝鸥科技. All rights reserved.
//

#import "Server.h"
#define PORT 9000



@implementation Server

- (void)beginConnect
{
    // 创建一个server socket引用
    CFSocketRef sserver;
    // 创建一个socket context
    CFSocketContext CTX = {0, nil, nil, nil, nil};
    
    // 创建server socket tcp ip4 设置回调函数, PF_INET为选择是socket连接；sock_stream是流传输即tcp；
    sserver = CFSocketCreate(nil, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, (CFSocketCallBack)AcceptCallBack, &CTX);
    
    if (sserver) {
        NSLog(@"服务器创建失败");
        return;
    }
    // 设置是否重新绑定标识
    int yes = 1;
    
//    设置socket属性 SOL_SOCKET是设置tcp SO_REUSEADDR重新绑定，yes是否重新绑定
    
    setsockopt(CFSocketGetNative(sserver), SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
    // 设置端口号和地址
    struct sockaddr_in addr;
    
    memset(&addr, 0, sizeof(addr)); // memset函数对制定的地址进行内存复制
    addr.sin_len = sizeof(addr);
    addr.sin_family = AF_INET;  // AF_INET是设置ipv4
    addr.sin_port = htons(PORT);// htons函数，五福好短整形数转换成“网络字节序”
    addr.sin_addr.s_addr = htonl(INADDR_ANY);// INADDR_ANY有内核分配，htonl函数 五福好长整型数转换为“网络字节序”
    
    // 从制定自己缓冲区复制，一个不可变的cfdata对象
    CFDataRef address = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&addr, sizeof(addr));
    
    // 绑定socket
    if (CFSocketSetAddress(sserver, (CFDataRef)address) != kCFSocketSuccess) {
        NSLog(@"绑定失败");
        CFRelease(sserver);
        return;
    }
    
    // 创建一个run loop socket源
    CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sserver, 0);
    // socket源添加到runloop中
    CFRunLoopAddSource(CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes);
    CFRelease(sourceRef);
    NSLog(@"socket listening on port %d", PORT);
    CFRunLoopRun();
    
}

// 接收到客户端请求后，回调函数
void AcceptCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
{
    CFReadStreamRef readStream = nil;
    CFWriteStreamRef writeStream = nil;
    
    // data 参数含义是：如果回调类型是kCFSocketAcceptCallBack，data就是CFSocketNativeHandle类型的指针
    CFSocketNativeHandle sock = * (CFSocketNativeHandle *)data;
    
    // 创建读写socket流
    CFStreamCreatePairWithSocket(kCFAllocatorDefault, sock, &readStream, &writeStream);
    if (!readStream || !writeStream) {
        close(sock);
        NSLog(@"创建读写数据流失败");
        return;
    }
    CFStreamClientContext streamCtxt = {0, nil, nil, nil, nil};
    
    // 注册两种回调函数
    CFReadStreamSetClient(readStream, kCFStreamEventHasBytesAvailable, ReadStreamClientCallBack, &streamCtxt);
    CFWriteStreamSetClient(writeStream, kCFStreamEventCanAcceptBytes, WriteStreamClientCallBack, &streamCtxt);
    
    // 加入到循环中
    CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    CFWriteStreamScheduleWithRunLoop(writeStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    
    CFReadStreamOpen(readStream);
    CFWriteStreamOpen(writeStream);
    
}


@end



